package mirkofrancuski.battleship.gui;

import mirkofrancuski.battleship.R;
import mirkofrancuski.battleship.game.Board;
import mirkofrancuski.battleship.game.Cell;
import mirkofrancuski.battleship.game.Coordinates;
import mirkofrancuski.battleship.game.Ship;
import mirkofrancuski.battleship.gui.DrawableShip.DrawableState;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;

public class PlayBoard extends GameBoard {
	private String DEBUG_TAG = "DEBUG PlayBoard";

	private final Bitmap mBitmapHit;
	private final Bitmap mBitmapMiss;

	private final Bitmap mBitmapSelectionVerticalOk;
	private final Bitmap mBitmapSelectionVerticalError;
	private final Bitmap mBitmapSelectionHorizontalOk;
	private final Bitmap mBitmapSelectionHorizontalError;

	private GestureDetector gestures;

	private class GestureListener extends
			GestureDetector.SimpleOnGestureListener implements
			GestureDetector.OnDoubleTapListener {

		@Override
		public boolean onDown(MotionEvent e) {
			Log.v(DEBUG_TAG, "onDown");
			selectShot(calcCoord(e.getX(), e.getY()));
			return true;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2,
				final float velocityX, final float velocityY) {
			Log.v(DEBUG_TAG, "onFling");
			return true;
		}

		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2,
				float distanceX, float distanceY) {
			Log.v(DEBUG_TAG, "onScroll");
			updateSelectedShot(calcCoord(e2.getX(), e2.getY()));
			return true;

		}
	}

	public PlayBoard(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		gestures = new GestureDetector(context, new GestureListener());

		Resources res = this.getResources();

		mBitmapHit = Bitmap.createScaledBitmap(
				BitmapFactory.decodeResource(res, R.drawable.hit), mCellWidth,
				mCellWidth, true);
		mBitmapMiss = Bitmap.createScaledBitmap(
				BitmapFactory.decodeResource(res, R.drawable.miss), mCellWidth,
				mCellWidth, true);
		mBitmapSelectionVerticalOk = Bitmap.createScaledBitmap(BitmapFactory
				.decodeResource(res, R.drawable.selection_vertical_ok),
				mCellWidth, mCellWidth * 10, true);
		mBitmapSelectionVerticalError = Bitmap.createScaledBitmap(BitmapFactory
				.decodeResource(res, R.drawable.selection_vertical_error),
				mCellWidth, mCellWidth * 10, true);
		mBitmapSelectionHorizontalOk = Bitmap.createScaledBitmap(BitmapFactory
				.decodeResource(res, R.drawable.selection_horizontal_ok),
				mCellWidth * 10, mCellWidth, true);
		mBitmapSelectionHorizontalError = Bitmap.createScaledBitmap(
				BitmapFactory.decodeResource(res,
						R.drawable.selection_horizontal_error),
				mCellWidth * 10, mCellWidth, true);


	}

	public PlayBoard(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(mCellWidth * 12, mCellWidth * 12);
	}

	private boolean clickable = true;
	
	@Override
	public void setClickable(boolean clickable) {
		super.setClickable(clickable);
		this.clickable = clickable;  
	}

	@Override
	protected void onDraw(Canvas canvas) {
		drawWholeBoard(canvas);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (!mMainBoard || !clickable)
			return false;

		boolean returnValue = gestures.onTouchEvent(event);

		if (event.getActionMasked() == MotionEvent.ACTION_UP) {
			Log.v(DEBUG_TAG, "ACTION_UP");
			unselectShot(calcCoord(event.getX(), event.getY()));
			returnValue = true;
		}

		return returnValue;
	}

	void drawWholeBoard(Canvas canvas) {
		for (DrawableShip ship : mShips) {
			ship.draw(canvas);
		}
		Coordinates coord = new Coordinates();
		for (int i = 0; i < Board.BOARD_SIZE; i++) {
			for (int j = 0; j < Board.BOARD_SIZE; j++) {
				coord.horizontal = i;
				coord.vertical = j;

				Cell cell = board.getCell(i, j);
				switch (cell) {
				case EMPTY:
					break;
				case MISS:
					canvas.drawBitmap(mBitmapMiss, calcX(j), calcY(i), null);
					break;
				case HIT:
					canvas.drawBitmap(mBitmapHit, calcX(j), calcY(i), null);
				default:
					if (mMainBoard)
						canvas.drawBitmap(mBitmapHit, calcX(j), calcY(i), null);
					break;
				}
			}
		}

		if (shotSelected)
			drawSelection(canvas);
	}

	Bitmap mBitmapSelectionHorizontal, mBitmapSelectionVertical;

	private void drawSelection(Canvas canvas) {
		if(!board.isInBounds(currCoordinates))
			return;
		

		if (board.isEmpty(currCoordinates)) {
			mBitmapSelectionHorizontal = mBitmapSelectionHorizontalOk;
			mBitmapSelectionVertical = mBitmapSelectionVerticalOk;
		} else {
			mBitmapSelectionHorizontal = mBitmapSelectionHorizontalError;
			mBitmapSelectionVertical = mBitmapSelectionVerticalError;
		}

		canvas.drawBitmap(mBitmapSelectionHorizontal, calcX(0),
				calcY(currCoordinates.horizontal), null);
		canvas.drawBitmap(mBitmapSelectionVertical,
				calcX(currCoordinates.vertical), calcY(0), null);
	}

	public Cell takeHit(Coordinates coord) {
		return board.takeHit(coord);
	}

	public void updateHit(Coordinates coord, Cell result) {
		DrawableShip dShip = selectDrawableShip(result);
		if (dShip != null) {
			dShip.setState(DrawableState.SUNKEN);
		}
		invalidate();
	}

	public void updateResult(Coordinates coord, Cell cell) {
		board.updateResult(coord, cell);
		invalidate();
	}
	
	public void updateResult(Ship ship) {
		board.updateResult(ship);
		
		DrawableShip sunkenShip = selectDrawableShip(ship.shipCell);
		if (sunkenShip.ship.direction != ship.direction)
			sunkenShip.rotate();
		sunkenShip.setBegining(ship.start);
		sunkenShip.place();
		sunkenShip.setState(DrawableState.SUNKEN);
				
		invalidate();
	}

	public boolean areAllShipsSunk() {
		return board.areAllShipsSunk();
	}

	private Coordinates currCoordinates = null;
	private Boolean shotSelected = false;
	private Coordinates selectedCoordinates = null;

	public Coordinates getSelectedCoordinates() {
		return selectedCoordinates;
	}

	public void selectShot(Coordinates touchCoordinates) {
		Log.v(DEBUG_TAG, "select");

		shotSelected = true;
		currCoordinates = new Coordinates(touchCoordinates);

		invalidate();
	}

	private void unselectShot(Coordinates touchCoordinates) {

		if (!board.isEmpty(touchCoordinates)) {
			selectedCoordinates = null;
		} else {
			selectedCoordinates = new Coordinates(touchCoordinates);
			Context context = getContext();
			synchronized (context) {
				context.notify();
			}
		}

		Log.v(DEBUG_TAG, "unselect");

		shotSelected = false;
		currCoordinates = null;
		invalidate();
	}

	private void updateSelectedShot(Coordinates touchCoordinates) {
		if (currCoordinates == touchCoordinates)
			return;

		currCoordinates = new Coordinates(touchCoordinates);

		Log.v(DEBUG_TAG, "update");

		invalidate();
	}

}
